/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#if !defined(AFX_Singleton_H__2355FD75_ECC0_4558_9EF9_D1B276CD203D__INCLUDED_)
#define AFX_Singleton_H__2355FD75_ECC0_4558_9EF9_D1B276CD203D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

/*! \defgroup Singletons
\ingroup AlgoToolsGroup
*/

/*! Singleton namespace.

Deriving your singleton from the Singleton template:

\code
  class MyClass : public Singleton< MyClass, 3 >
  {
  ...
  };
\endcode
where 3 is the destruction phase.
*/
namespace singletons
{


class CDestructionPhase 
{
        int m_phase;
public:
        explicit CDestructionPhase (int phase) : m_phase(phase) {};


        bool operator> (const CDestructionPhase& dp) const
        { return m_phase > dp.m_phase; };
};


class CDestructor;


class CDestructionManager 
{
        typedef std::auto_ptr<CDestructionManager> DestructionManagerPtr;
        static DestructionManagerPtr& GetInstance();
        CDestructionManager() {};
        ~CDestructionManager();
        friend DestructionManagerPtr;


        std::vector<CDestructor*> m_destructors;
public:
        // Singleton interface
        static CDestructionManager& Instance() { return *GetInstance(); };
        void RegisterDestructor(CDestructor* Destructor)
        { 
                m_destructors.push_back(Destructor); 
        };
        void DestroyObjects(); // destroy the objects
};


class CDestructor 
{
        CDestructionPhase m_dphase;
public:
        CDestructor(CDestructionPhase dphase) : m_dphase(dphase)
        { 
                CDestructionManager::Instance().RegisterDestructor(this); 
        }
        bool operator>(const CDestructor& Destructor) const
        { 
                return m_dphase > Destructor.m_dphase; 
        }
        virtual void Destroy() = 0;
};


template <class T> class TDestructor : public CDestructor 
{
public:
        TDestructor(CDestructionPhase dphase)
                : CDestructor(dphase) {};
        void Destroy() {	T::DestroyInstance(); };
};


template <class _S, int _DestructionPhase>
class TSingleton
{
		typedef  std::auto_ptr<_S> InstancePtr;
        //! return by reference to prevent transfer of ownership
        static InstancePtr& GetInstance()
        {       
                static InstancePtr sInstance(new _S); 
                if (sInstance.get() == NULL)
                        throw _T("Could not create Singleton");
                static TDestructor<TSingleton<_S, _DestructionPhase> > * destructor_ = 
					new TDestructor<TSingleton<_S, _DestructionPhase> >(CDestructionPhase(_DestructionPhase)); 
                return sInstance; 
        };
        //! destroys the instance
        static void DestroyInstance() {    delete GetInstance().release(); };


        //! to allow auto_ptr delete the Singleton
        friend InstancePtr;
        friend class
           TDestructor<TSingleton<_S, _DestructionPhase> >;


        //! Singletons should not be copied
        TSingleton(const TSingleton&);
        TSingleton& operator=(const TSingleton&);
protected:
        TSingleton() {}
public:
		static unsigned GetPhase()		{	return _DestructionPhase;};
        static _S* Instance()		{	return GetInstance().get();};
        static _S& InstanceRef()	{   return *GetInstance().get();};
};



class CDestroyObjects 
{
public:
        ~CDestroyObjects()
        { CDestructionManager::Instance().DestroyObjects(); };
};


};

#endif // !defined(AFX_Singleton_H__2355FD75_ECC0_4558_9EF9_D1B276CD203D__INCLUDED_)
